# -*- coding: utf-8 -*-
# Proyecto 2 Entrega 1
# Lenguaje para graficar funciones y datos
# Traductores e Interpretadores (CI-3725)
# Autores: Carlos Jose Chitty   07-41896
#          Alejandro Rodriguez  04-37507

import sys
import lex
import yacc

__author__ = "Alejandro Rodriguez & Carlos Chitty"
__date__ = "$Jun 28, 2010 9:05:37 PM$"

# Definiendo los tokens
tokens = (
          'NUMEROS', 'PI', 'E','VARIABLES','PARENTESISDER', 'PARENTESISIZQ', 'RANGE',
          'MAS', 'MENOS', 'POR', 'ENTRE', 'POTENCIA', 'CORCHETEIZQ', 'CORCHETEDER', 'COMA',
          'SIN', 'COS', 'TAN', 'EXP', 'LOG', 'CIEL', 'FLOOR', 'FOR', 'IN', 'MAYOR', 'MENOR',
          'MAYOROIGUAL', 'MENOROIGUAL', 'EQUIVALENTE', 'IF', 'AND', 'OR', 'NOT' '\'FILE\'',
          )

# Palabras reservadas
reserved = {    'pi':'PI',
                'e':'E',
                'lines':'LINES',
                'points':'POINTS',
                'linespoints':'LINESPOINTS',
                'with':'WITH',
                'for':'FOR',
                'endfor':'ENDFOR',
                'in':'IN',
                'range':'RANGE',
                'plot':'PLOT',
                'if':'IF',
                'sin':'SIN',
                'cos':'COS',
                'tan':'TAN',
                'exp':'EXP',
                'log':'LOG',
                'ciel':'CIEL',
                'floor':'FLOOR',
                'OR':'OR',
                'AND':'AND',
                'NOT':'NOT',
}


t_ignore = ' \t'

# Definiendo las gramaticas
# Gramatica para numeros
def t_NUMEROS(t):
    r'[0-9]+(\.[0-9]+(e[+-][0-9]+)?)?'
    return t

# Gramatica para variables
def t_VARIABLES(t):
    r'[A-Za-z]+'
    t.type = reserved.get(t.value,'VARIABLES')
    return t

# Gramatica para parentesis
t_PARENTESISIZQ = r'\('
t_PARENTESISDER = r'\)'
t_CORCHETEIZQ = r'\['
t_CORCHETEDER = r'\]'

# Gramatica para signos de expresion matematica
t_MAS = r'\+'
t_MENOS = r'\-'
t_POR = r'\*'
t_ENTRE = r'\/'
t_POTENCIA = r'\^'
t_COMA = r','
t_MAYOR = r'>'
t_MENOR = r'<'
t_MAYOROIGUAL = r'>='
t_MENOROIGUAL = r'<='
t_EQUIVALENTE = r'=='

# Definiendo para casos de error
def t_error(t):
    print "Caracter inválido '%s'" % t.value[0] + '. Linea: ' + str(t.lineno) + '. Columna ' + str(t.lexpos) + '.'
    sys.exit()


lexar = lex.lex()

# Precedencia de operadores
precedence = (
    ('left','MAS','MENOS'),
    ('left','POR','ENTRE'),
    ('left','POTENCIA'),
    ('right','COMA'),
    ('left','OR'),
    ('left','AND'),
    ('right','NOT'),
    ('nonasoc','MAYOR','MENOR','MENOROIGUAL','MAYOROIGUAL','EQUIVALENTE' )
    )

def p_em_mas(p):
    'expression : expression MAS expression'
    p[0]= ('Suma', p[1],p[3])

def p_em_menos(p):
    '''expression : expression MENOS expression
                  | MENOS expression'''
    if len(p) == 4 : 
        p[0]=('Resta', p[1], p[3])
    if len(p) == 3 :
        p[0]=('Negativo', p[1])

def p_em_por(p):
    'expression : expression POR expression'
    p[0]=('Multiplicacion',p[1],p[3])

def p_em_entre(p):
    'expression : expression ENTRE expression'
    p[0]=('Division',p[1],p[3])

def p_em_potencia(p):
    'expression : expression POTENCIA expression'
    p[0]=('Potencia',p[1],p[3])

def p_em_numeros(p):
    'expression : NUMEROS'
    p[0]=('Numeros',p[1])

def p_em_parentesis(p):
    'expression : PARENTESISIZQ expression PARENTESISDER'
    p[0]=p[2]

def p_em_variables(p):
    'expression : VARIABLES'
    p[0]=('Variables',p[1])

def p_em_funciones(p):
    '''expression : fReservadas PARENTESISIZQ expression PARENTESISDER
                  | fReservadas'''
    p[0]=('Funcion',('Nombre',p[1]), p[3])

def p_em_func_if(p):
    'expression : IF PARENTESISIZQ condicion COMA expression COMA expression PARENTESISDER'
    p[0] = ('Funcion Especial If',p[3],p[5],p[7])

def p_em_condicion(p):
    '''condicion : expression
                  | condicion AND condicion
                  | condicion OR condicion
                  | condicion MAYOR condicion
                  | condicion MENOR condicion
                  | condicion MAYOROIGUAL condicion
                  | condicion MENOROIGUAL condicion
                  | condicion EQUIVALENTE condicion
                  | NOT condicion'''
    if len(p)==4 :
        p[0] = ('Condicion',p[2],p[1],p[3])
    elif len(p)==3:
        p[0] = ('Condicion',p[1],p[2])
    elif len(p)==2:
        p[0] = ('Condicion',p[1])

def p_em_fReservadas(p):
    '''fReservadas : SIN
                   | COS
                   | TAN
                   | EXP
                   | LOG
                   | CIEL
                   | FLOOR
                   | VARIABLES'''
    p[0]=p[1]

def p_em_arreglos(p):
    '''expression : CORCHETEIZQ CORCHETEDER
                  | CORCHETEIZQ elementoArreglo CORCHETEDER'''
    if len (p) == 3 :
        p[0] = ('Arreglo Vacio')
    elif len(p) == 4 :
        p[0] = ('Arreglo',p[2])

def p_em_elementoArreglo(p):
    '''elementoArreglo : expression
                       | elementoArreglo COMA expression'''
    if len (p) == 4 :
        p[0] = (p[1], p[3])
    elif len(p) == 2 :
        p[0] = ('Expresion', p[1])

def p_em_arreglosComprension(p):
    'expression : CORCHETEIZQ expression FOR VARIABLES IN expression CORCHETEDER'
    p[0] = ('Arreglo por comprension',p[2],('Variable',p[4]),p[6])

def p_em_range(p):
    'expression : RANGE PARENTESISIZQ expression COMA expression PARENTESISDER'
    p[0] = ('Range', p[3], p[5])

def p_error(p):
    print "Se ha detectado un error."
    sys.exit(1)

parser= yacc.yacc()

if __name__ == "__main__":
    print "Output: "
    s = 'if (1 AND NOT 2,x+2,y-9)'
    lexar.input(s)
    for tok in lexar:
        print tok
    resultado = parser.parse(s,lexer = lexar)#,debug = 1)
    print resultado